﻿// Inner Fire 游戏引擎库
// AnimatorTransforms - 动画机变换矩阵列表
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 用于临时保存一个变换矩阵，然后用于最后的混合。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-05-16

#include "snapshot.h"
#include <game/animation/animation.h>
#include <graphics/imath.h>
#include <klog.h>

using namespace DirectX;

namespace ifire::game {
Snapshot::Snapshot(int index, size_t bone_count)
    : index_(index)
    , bone_count_(bone_count)
    , transforms(bone_count)
    , is_used_(false)
    , weight(0.0f)
    , root_motion(this)
    , clip(nullptr)
    , frame(0.0f) {}

void Snapshot::Mix(const Snapshot& a, const Snapshot& b) {
  // 得到权重的Lerp
  float lerp = a.weight / (a.weight + b.weight);
  // 合并RootMotion
  SetDelta(XMVectorLerp(a.GetDelta(), b.GetDelta(), lerp));
  // 合并骨骼
  for (size_t i = 0; i < bone_count_; i++) {
    transforms[i] = imath::MatrixLerp(a.transforms[i], b.transforms[i], lerp);
  }
}

void Snapshot::SetCurrent(AnimationClip* _clip, float _frame) {
  // 如果发生变化，则清空RootMotion
  if (this->clip && this->clip != _clip) {
    root_motion.Reset();
  }

  this->clip = _clip;
  this->frame = _frame;
  this->root_motion.SetRootMotionAxis(_clip->GetRootMotionAxis());
}

void Snapshot::ExecuteRootMotion(IMat& mat) { root_motion.Execute(frame, mat); }

void Snapshot::PassRootMotion() { root_motion.Reset(); }

Snapshots::Snapshots(size_t bone_count) : bone_count_(bone_count) {
  // 创建位置0的项目
  Get(0);
}

Snapshot& Snapshots::Get(int slot) {
  if (slot < items_.size()) {
    return *items_[slot].get();
  }

  // 计算应该创建多少个，比如，当前只有一个，Slot却定位到了3，就不能只创建一个
  size_t create_count = (slot + 1) - size();
  for (size_t i = 0; i < create_count; i++) {
    int index = static_cast<int>(items_.size());
    auto item = std::make_unique<Snapshot>(index, bone_count_);
    items_.emplace_back(std::move(item));
  }

  // 这时已经确定拥有项目，不需要检查
  return *items_[slot].get();
}

void Snapshots::ClearUsed() {
  for (auto& i : items_) {
    i->SetUsed(false);
    i->weight = 0.0f;
  }
}

void Snapshots::Mix(int a_index, int b_index, int store_index) {
  auto& a = Get(a_index);
  auto& b = Get(b_index);
  auto& c = Get(store_index);
  c.Mix(a, b);
}

void Snapshots::Pick(int from_index, int to_index) {
  auto& f = Get(from_index);
  auto& t = Get(to_index);
  // 直接进行复制
  for (int i = 0; i < bone_count_; i++) {
    t.transforms[i] = f.transforms[i];
  }
}

size_t Snapshots::GetUsedCount() {
  size_t used_count = 0;
  for (auto& e : items_) {
    if (e->IsUsed()) {
      used_count++;
    }
  }
  return used_count;
}

} // namespace ifire::game